package com.ts.api.module.api.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.gitee.apanlh.spring.BeanContextUtils;
import com.gitee.apanlh.util.base.Eq;
import com.gitee.apanlh.util.base.StringUtils;
import com.gitee.apanlh.util.dataformat.JsonUtils;
import com.gitee.apanlh.util.date.DateUtils;
import com.gitee.apanlh.util.reflection.ClassConvertUtils;
import com.gitee.apanlh.util.reflection.CopyUtils;
import com.gitee.apanlh.util.valid.ValidParam;
import com.gitee.apanlh.web.model.vo.RequestVO;
import com.ts.api.common.constant.productflow.ProductApplyFlowSrcTypeEnum;
import com.ts.api.common.constant.productflow.ProductApplyFlowStatusEnum;
import com.ts.api.common.context.ApiContext;
import com.ts.api.common.redis.ApiMatchRedisKey;
import com.ts.api.common.redis.ChannelMatchRedisKey;
import com.ts.api.module.api.convert.core.entity.ApiBizStatus;
import com.ts.api.module.api.convert.core.http.client.ApiHttpMessage;
import com.ts.api.module.api.convert.platform.context.ApiPlatformConvertContext;
import com.ts.api.module.api.convert.platform.entity.RespPlatformNoticeApply;
import com.ts.api.module.api.convert.platform.handler.ApiPlatformPhoneMd5ConvertHandler;
import com.ts.api.module.api.convert.receive.entity.ApiReceiveNotice;
import com.ts.api.module.api.convert.receive.http.ApiReceiveNoticeHttpHandler;
import com.ts.api.module.api.entity.po.ApiKeyPO;
import com.ts.api.module.api.entity.po.ApiLogPO;
import com.ts.api.module.api.entity.vo.ReqApiParameterVO;
import com.ts.api.module.api.service.ApiBizApplyNoticeService;
import com.ts.api.module.api.service.ApiBizRequiredService;
import com.ts.api.module.channel.service.ChannelProductMatchService;
import com.ts.api.module.product.entity.po.ProductApplyFlowPO;
import com.ts.api.module.product.entity.po.ProductPO;
import com.ts.api.module.product.entity.po.ProductPlanPO;
import com.ts.api.module.product.entity.qo.ProductApplyFlowQO;
import com.ts.api.module.product.service.ProductApplyFlowService;
import com.ts.cache.apikey.ApiKeyCacheService;
import com.ts.cache.apikey.entity.ApiKeyCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Map;

@Service
public class ApiBizApplyNoticeServiceImpl implements ApiBizApplyNoticeService {

    @Autowired
    private ApiBizRequiredService apiBizRequiredService;
    @Autowired
    private ProductApplyFlowService productApplyFlowService;
    @Autowired
    private ApiReceiveNoticeHttpHandler apiReceiveNoticeHttpHandler;
    @Autowired
    private ApiKeyCacheService apiKeyCacheService;
    @Autowired
    private ApiPlatformConvertContext apiPlatformConvertContext;
    @Autowired
    private ChannelProductMatchService channelProductMatchService;

    @Override
    public Map<String, Object> applyAcceptNotice(RequestVO requestVO, ProductPO productPO, ProductPlanPO productPlanPO) {
        //  获取平台事件上下文
        ApiPlatformPhoneMd5ConvertHandler platFrom = apiPlatformConvertContext.getPlatformPhoneMd5(productPlanPO);

        //  1.接收-解析下游回调请求(我方接入、对方接入)
        RespPlatformNoticeApply respPlatFormNoticeApply = platFrom.parseApplyNotice(requestVO);
        //  如果phoneMd5为空则根据applyId置换phoneMd5
        String phoneMd5 = respPlatFormNoticeApply.getPhoneMd5();
        if (ValidParam.isEmpty(phoneMd5)) {
            String applyId = respPlatFormNoticeApply.getApplyId();
            String dtaMapKey = ApiMatchRedisKey.getDataExchangeUniqueIdByApplyId(productPO.getId(), productPlanPO.getId(), applyId);
            String dataMapJson = ApiMatchRedisKey.DOWNSTREAM_EXTEND.get(dtaMapKey, String.class);
            Map<String, String> valueMap = JsonUtils.toBean(dataMapJson, new TypeReference<>() {});
            phoneMd5 = valueMap.get("phoneMd5");
            //  销毁key
            ApiMatchRedisKey.DOWNSTREAM_EXTEND.delKey(dtaMapKey);
        }
        phoneMd5 = StringUtils.lowerStr(phoneMd5);

        //  2.获取API渠道-下游半流程回调流程表数据
        ProductApplyFlowQO noticeCallback = ProductApplyFlowQO.createNoticeCallback(productPO.getId(), productPlanPO.getId(), phoneMd5);
        ProductApplyFlowPO productApplyFlowPO = productApplyFlowService.get(noticeCallback);
        if (ValidParam.isNull(productApplyFlowPO)) {
            //  2.获取自有渠道-下游版流程申请数据
            String channelNoticeFlowKey = ChannelMatchRedisKey.getDataExchangeUniqueIdByPhoneMd5(productPO.getId(), productPlanPO.getId(), phoneMd5);
            ProductApplyFlowPO channelProductApplyFlowPO = ChannelMatchRedisKey.CHANNEL_APPLY_NOTICE_FLOW.get(channelNoticeFlowKey, ProductApplyFlowPO.class);
            if (channelProductApplyFlowPO == null) {
                return platFrom.respApplyNotice(ApiBizStatus.fail("无对应流程"));
            }
            productApplyFlowPO = channelProductApplyFlowPO;
        }

        //  日志-请求参数及业务日志信息
        ReqApiParameterVO reqApiParameterVO = ReqApiParameterVO.createByPhoneMd5(phoneMd5);
        reqApiParameterVO.getFormMap().put("city", productApplyFlowPO.getAreaName());
        ApiContext.REQ_PARAMS.set(reqApiParameterVO);
        ApiContext.SERVICE_CODE.set("下游进件申请");
        ApiLogPO logPO = ApiContext.LOG_OBJECT.get();
        if (ValidParam.isNotNull(logPO)) {
            logPO.setApiClientId(productPO.getName() + "-" + productPlanPO.getDisplayName());
        }

        //  修改-日志请求id-一致id
        ApiContext.REQ_ID.remove();
        ApiContext.REQ_ID.set(ClassConvertUtils.toStr(productApplyFlowPO.getReqId()));

        //  3.请求-发送上游进件通知，并解析上游进件通知
        String apiClientId = productApplyFlowPO.getApiClientId();

        //  上游-拉取进件流程日志
        ProductApplyFlowPO pullNoticeProductApplyFlowPO = new ProductApplyFlowPO();
        pullNoticeProductApplyFlowPO.setApiClientId(productApplyFlowPO.getApiClientId());
        pullNoticeProductApplyFlowPO.setLoanChannelId(productApplyFlowPO.getLoanChannelId());
        pullNoticeProductApplyFlowPO.setLoanProductId(productApplyFlowPO.getLoanProductId());
        pullNoticeProductApplyFlowPO.setLoanProductPlanId(productApplyFlowPO.getLoanProductPlanId());
        pullNoticeProductApplyFlowPO.setReqId(productApplyFlowPO.getReqId());
        pullNoticeProductApplyFlowPO.setSrcType(ProductApplyFlowSrcTypeEnum.API.getType());
        pullNoticeProductApplyFlowPO.setStatus(ProductApplyFlowStatusEnum.CHANNEL_PULL_APPLY_NOTICE.getType());
        pullNoticeProductApplyFlowPO.setPhoneMd5(productApplyFlowPO.getPhoneMd5());
        pullNoticeProductApplyFlowPO.setCreateTime(DateUtils.currentTime());
        pullNoticeProductApplyFlowPO.setBizStatus("0");
        pullNoticeProductApplyFlowPO.setAreaName(productApplyFlowPO.getAreaName());
        pullNoticeProductApplyFlowPO.setAreaCode(productApplyFlowPO.getAreaCode());
        pullNoticeProductApplyFlowPO.setCallUrl(productPO.getApiApplyUrl());

        //  自有渠道-无须拉取上游
        if (ValidParam.isEmpty(productApplyFlowPO.getApiClientId())) {
            //  插入上游回调流程日志
            pullNoticeProductApplyFlowPO.setReqData("自有渠道无须拉取上游");
            pullNoticeProductApplyFlowPO.setBizStatus("1");
            productApplyFlowService.insert(pullNoticeProductApplyFlowPO, false);

            //  删除拉取通知key
            String channelNoticeFlowKey = ChannelMatchRedisKey.getDataExchangeUniqueIdByPhoneMd5(productPO.getId(), productPlanPO.getId(), phoneMd5);
            ChannelMatchRedisKey.CHANNEL_APPLY_NOTICE_FLOW.delKey(channelNoticeFlowKey);

            //  直接进件下游流程
            channelProductMatchService.callbackNoticeApply(productPO, productPlanPO, productApplyFlowPO, phoneMd5);
            return platFrom.respApplyNotice(ApiBizStatus.suc());
        }

        //  如果开启测试环境则直接自己向自己发起进件
        if (Eq.str("test", BeanContextUtils.getApplicationContext().getEnvironment().getActiveProfiles()[0])) {
            //  插入上游回调流程日志
            pullNoticeProductApplyFlowPO.setReqData("测试环境无需拉取上游");
            pullNoticeProductApplyFlowPO.setBizStatus("1");
            productApplyFlowService.insert(pullNoticeProductApplyFlowPO, false);
            return platFrom.respApplyNotice(ApiBizStatus.suc());
        }

        //  3.1将上游通知进件结果保存redis中，上游进件时则根据此标识进件给下游(applyV2接口)
        String applyNoticeFlowKey = ApiMatchRedisKey.getApplyNoticeFlowKey(productApplyFlowPO.getApiClientId(), productApplyFlowPO.getLoanProductPlanId(), productApplyFlowPO.getPhoneMd5());
        ApiMatchRedisKey.API_CHANNEL_APPLY_NOTICE_FLOW.setForMinutes(applyNoticeFlowKey, productApplyFlowPO.getLoanProductPlanId(), 10L);

        //  上游-拉取消息实体类
        ApiKeyCache apiKeyCache = apiKeyCacheService.get(apiClientId);
        ApiKeyPO apiKeyPO = CopyUtils.copy(apiKeyCache, ApiKeyPO.class);

        ApiReceiveNotice pullNoticeMessage = new ApiReceiveNotice();
        pullNoticeMessage.setReqId(String.valueOf(productApplyFlowPO.getReqId()));
        pullNoticeMessage.setProductId(productPO.getId());
        pullNoticeMessage.setApiClientId(apiClientId);
        pullNoticeMessage.setPhoneMd5(productApplyFlowPO.getPhoneMd5());

        //  拉取上游通知
        ApiHttpMessage apiPullNoticeHttpMessage = apiReceiveNoticeHttpHandler.sendPullApplyNotice(apiKeyPO, pullNoticeMessage);
        if (ValidParam.isNull(apiPullNoticeHttpMessage)) {
            ApiMatchRedisKey.API_CHANNEL_APPLY_NOTICE_FLOW.delKey(applyNoticeFlowKey);
            pullNoticeProductApplyFlowPO.setExceptionMsg("无配置上游进件回调地址");
            productApplyFlowService.insert(pullNoticeProductApplyFlowPO, true);
            return platFrom.respApplyNotice(ApiBizStatus.fail("无配置上游进件回调地址"));
        }

        //  记录上游拉取进件回调流程日志
        pullNoticeProductApplyFlowPO.setReqData(String.valueOf(apiPullNoticeHttpMessage.getRequestBody()));
        pullNoticeProductApplyFlowPO.setRespData(apiPullNoticeHttpMessage.getResponseBody());
        pullNoticeProductApplyFlowPO.setRespCode(String.valueOf(apiPullNoticeHttpMessage.getRespCode()));
        boolean hasPullNoticeHttpRespSuc = apiBizRequiredService.hasNoticeHttpRespSuc(pullNoticeProductApplyFlowPO, apiPullNoticeHttpMessage, ProductApplyFlowStatusEnum.CHANNEL_PULL_APPLY_NOTICE);

        if (!hasPullNoticeHttpRespSuc) {
            //  销毁
            ApiMatchRedisKey.API_CHANNEL_APPLY_NOTICE_FLOW.delKey(applyNoticeFlowKey);
            return platFrom.respApplyNotice(ApiBizStatus.fail("上游进件回调返回失败"));
        }

        //  插入上游回调流程日志
        pullNoticeProductApplyFlowPO.setBizStatus("1");
        productApplyFlowService.insert(pullNoticeProductApplyFlowPO, false);

        //  4.返回-下游进件回调通知结果
        return platFrom.respApplyNotice(ApiBizStatus.suc());
    }
}
